# -*- coding:utf-8 -*-
# -*- author：zzZ_CMingfrom tensorflow.examples.tutorials.mnist import input_data
# -*- 2018/02/05；09:58
# -*- python3.5

from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
#循环神经网络
# #读取MNIST数据集
# mnist = input_data.read_data_sets('MNIST_data',one_hot = True)
#
# training_iters = 50001
# batch_size = 100          #批量大小
#
# n_inputs = n_steps = 28
# n_hidden_number = 128    #隐藏层神经元个数
# n_outputs = 10           #输出层神经元个数
#
# #预定义输入值X、输出真实值Y    placeholder为占位符
# x = tf.placeholder(tf.float32,[None,n_steps,n_inputs])
# Y = tf.placeholder(tf.float32,[None,n_outputs])
#
# weights = {
#     # shape = (28,128)
#     'in':tf.Variable(tf.random_normal([n_inputs,n_hidden_number])),
#     # shape = (128,10)
#     'out':tf.Variable(tf.random_normal([n_hidden_number,n_outputs]))}
#
# biases = {
#     # shape = (128,)
#     'in':tf.Variable(tf.constant(0.1,shape = [n_hidden_number,])),
#     # shape = (10,)
#     'out':tf.Variable(tf.constant(0.1,shape = [n_outputs,]))}
#
#
# def RNN(X,weights,biases):
#     ### 输入层到核运算 ###
#     # X shape = (100batch,28steps,28inputs) ==> (100batch*28steps,28inputs)
#     X = tf.reshape(X,[-1,n_inputs])
#     # X_in shape ==> (100batch*28steps,128hidden)
#     X_in = tf.matmul(X,weights['in'])+biases['in']
#     # X_in shape ==> (100batch,28steps,128hidden)
#     X_in = tf.reshape(X_in,[-1,n_steps,n_hidden_number])
#
#     ### cell核内运算 ###
#     lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(n_hidden_number,forget_bias = 1.0)
#     # LSTM cell is divided into two parts-->(c_state,m_state)
#     init_state = lstm_cell.zero_state(batch_size,dtype=tf.float32)
#     outputs,states = tf.nn.dynamic_rnn(lstm_cell,X_in,initial_state=init_state,time_major=False)
#
#     ### 核内运算到输出层 ###
#     result = tf.matmul(states[1],weights['out'])+biases['out']
#     return  result
#
#
# prediction = RNN(x,weights,biases)
# #二次代价函数:预测值与真实值的误差
# loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=Y, logits=prediction))
# #梯度下降法:数据庞大,选用AdamOptimizer优化器
# train_step = tf.train.AdamOptimizer(1e-3).minimize(loss)
# #结果存放在一个布尔型列表中
# correct_prediction = tf.equal(tf.argmax(prediction,1), tf.argmax(Y,1))
# #求准确率
# accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
#
# init = tf.global_variables_initializer()
# with tf.Session() as sess:
#     sess.run(init)
#     step = 0
#     while step*batch_size < training_iters:
#         batch_xs,batch_ys = mnist.train.next_batch(batch_size)
#         # batch_xs shape = [100,28,28]
#         batch_xs = batch_xs.reshape([batch_size,n_steps,n_inputs])
#         train_step.run(feed_dict={x:batch_xs,Y:batch_ys,})
#         if step%50 == 0:
#             train_accuracy = accuracy.eval(feed_dict={x:batch_xs,Y:batch_ys,})
#             print("step", step, "training accuracy", train_accuracy)
#         step += 1

# 权重
def weight_variable(shape):
    # 产生随机变量
    # truncated_normal：选取位于正态分布均值=0.1附近的随机值
    initial = tf.truncated_normal(shape, stddev=0.1)
    return tf.Variable(initial)

#偏置函数
def bias_variable(shape):
    initial = tf.constant(0.1, shape=shape)
    return tf.Variable(initial)

#卷积函数
def conv2d(x, W):
    #stride = [1,水平移动步长,竖直移动步长,1]
    return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')

#池化函数
def max_pool_2x2(x):
    # stride = [1,水平移动步长,竖直移动步长,1]
    return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],
                          strides=[1, 2, 2, 1], padding='SAME')

#读取MNIST数据集
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
sess = tf.InteractiveSession()

#预定义输入值X、输出真实值Y    placeholder为占位符
x = tf.placeholder(tf.float32, shape=[None, 784])
y_ = tf.placeholder(tf.float32, shape=[None, 10])
keep_prob = tf.placeholder(tf.float32)
x_image = tf.reshape(x, [-1,28,28,1])
#print(x_image.shape)  #[n_samples,28,28,1]

#卷积层1网络结构定义
#卷积核1：patch=5×5;in size 1;out size 32;激活函数reLU非线性处理
W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])
# b_conv1 = tf.variable([32])
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1) #output size 28*28*32
h_pool1 = max_pool_2x2(h_conv1)                          #output size 14*14*32

#卷积层2网络结构定义
#卷积核2：patch=5×5;in size 32;out size 64;激活函数reLU非线性处理
W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2) #output size 14*14*64
h_pool2 = max_pool_2x2(h_conv2)                          #output size 7 *7 *64

# 全连接层1
W_fc1 = weight_variable([7*7*64,1024])
b_fc1 = bias_variable([1024])
h_pool2_flat = tf.reshape(h_pool2, [-1,7*7*64])   #[n_samples,7,7,64]->>[n_samples,7*7*64]
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob) # 减少计算量dropout

#二次代价函数:预测值与真实值的误差
# 全连接层2
W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
prediction = tf.matmul(h_fc1_drop, W_fc2) + b_fc2
#prediction = tf.nn.softmax(stf.matmul(h_fc1_drop, W_fc2) + b_fc2)

loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=prediction))
#梯度下降法:数据太庞大,选用AdamOptimizer优化器
train_step = tf.train.AdamOptimizer(1e-4).minimize(loss)
#结果存放在一个布尔型列表中
correct_prediction = tf.equal(tf.argmax(prediction,1), tf.argmax(y_,1))
#求准确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

saver = tf.train.Saver()  # defaults to saving all variables
sess.run(tf.global_variables_initializer())

for i in range(901):
    batch = mnist.train.next_batch(50)
    if i%100 == 0:
        train_accuracy = accuracy.eval(feed_dict={x:batch[0], y_: batch[1], keep_prob: 1.0})
        print("step",i, "training accuracy",train_accuracy)
    train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})

#保存模型参数
saver.save(sess, './model.ckpt')
print("test accuracy %g"%accuracy.eval(feed_dict={x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))
